package com.ys.可变字符串;

/**
 * 描述:
 * StringBuffer类和StringBuilder类非常类似，都是继承自抽象类AbstractStringBuilder类，
 * 均代表可变的Unicode字符序列。StringBuilder类和StringBuffer类方法几乎一模一样，
 * 不过StringBuilder不是线程安全的，这是和StringBuffer的主要区别：
 * StringBuffer线程安全，做线程同步检查，效率较低。
 * StringBuilder线程不安全，不做线程同步检查，因此效率较高（推荐使用）。
 * 因为JDK1.5版本之前只有一个StringBuffer类（线程安全），
 * 由于发现利用多线程对同一字符串数据操作的情况是很少的，
 * 为了提高效率JDK1.5以后就有了StringBuilder类，
 * StringBuilder类提供一个与StringBuffer兼容的API，
 * 所以StringBuilder类和StringBuffer类的方法和功能完全一致。
 * --------------------------------------------------------------
 * StringBuffer和StringBuilder的运行效率几乎一致，这是因为二者都是对对象本身进行操作，不会生成新的字符串对象。二者的区别主要是StringBuffer是线程安全的，
 * 而StringBuilder是线程不安全的，所以StringBuilder的运行效率略高于StringBuffer。
 * String是不可变的对象，每次对String进行操作的时候，都会生成一个新的对象（StringBuilder），占用大量内存空间，这会对系统的性能造成影响，执行效率最低。
 * 所以在平时编程的过程中，如果字符串需要经常改变，应该尽量避免使用String。
 * ---------------------------------------------------------------
 * @author CodeYang
 * @version 2020/12/22 19:56
 */
public class StringBuilder类详解 {

    public static void main(String[] args) {
        f1();
        f2();
        f3();
    }

    /**
     * 重点:--在于编译器是否能提前确定 变量是否是一个可以提前确定的值(是否添加final)
     * 编译器,对于 str类型的变量的拼接,且无法提前确定其值,底层采用StringBuilder 机制去操作和拼接
     * 两个字符串拼接,有一个是 变量 不是常量:
     * <p>
     * hw在编译期并不能确定值，因为str是变量，JVM在运行期才能确定其值
     * 会在运行期时，进行字串拼接生成新的字串对象,通过javap -c Test查看虚拟机指令
     * 我们发现“String hw = str + "world";”其实等效于：
     * // 第一步; 创建 StringBuilder 的无参构造方法
     * StringBuilder sb = new StringBuilder();
     * // 第二部  sb.append(Type index) (任意类型) 追加,不会产生新的可变字符串
     * sb.append(str);
     * // 第三步把 字符串常量 继续追加
     * sb.append("world");
     * // 第四步 把 StringBuilder toString() 返回一个新的String 对象
     * String hw = sb.toString();
     * </p>
     * 所以hw == helloWorld 输出false
     */
    private static void f3() {
        String str = "hello";
        String hw = str + "world";
        String helloWolrd = "helloworld";
        System.out.println(hw == helloWolrd); // 输出：false
    }

    /**
     * 字符串拼接原理分析
     * 直接字符串常量拼接，对于编译期就能确定的值，编译器会将值合并
     * String hw = "hello" + "world";
     * 我们反编译字节码文件，就会将看到 : String hw = "helloworld";
     * <p>
     * 所以hw == helloWorld 输出true
     */
    private static void f1() {
        String hw = "hello" + "world"; // 等于：String hw = "helloworld";
        String helloWorld = "helloworld";
        System.out.println(hw == helloWorld); // 输出：true

    }

    /**
     * String hw = h + "world";虽然包含变量h的运算，但是编译器
     * 对final变量在编译期能确定其值，会发生宏替换，即：h变量替换成其值"hello"，
     * 然后编译器会对直接量字串直接合并
     * String hw = h + "world";在编译完后就变成了 String hw = "helloworld";
     * <p>
     * 所以hw == helloWorld 输出true
     */
    private static void f2() {
        final String h = "hello"; // final修饰的是常量
        String hw = h + "world"; // 等于：String hw = "helloworld";
        String helloWorld = "helloworld";
        System.out.println(hw == helloWorld); // 输出：true
    }
}
